using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;

/// <summary>
/// mono扩展
/// </summary>
public static class MonoExtension
{
    #region Transfrom
    /// <summary>
    /// 世界移动
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetPostion">目标位置</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoMove(this Transform transform, Vector3 targetPostion, float duration)
    {
        if (Vector3.Distance(transform.position, targetPostion) <= 0.01f)
        {
            Debug.LogWarning("transform postion is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startPostion = transform.position;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.position = Vector3.Lerp(startPostion, targetPostion, lerp);
            await Task.Yield();
        }
        transform.position = targetPostion;
    }

    /// <summary>
    /// 本地移动
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetPostion">目标位置</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoLocalMove(this Transform transform, Vector3 targetPostion, float duration)
    {
        if (Vector3.Distance(transform.localPosition, targetPostion) <= 0.01f)
        {
            Debug.LogWarning("transform postion is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startPostion = transform.localPosition;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.localPosition = Vector3.Lerp(startPostion, targetPostion, lerp);
            await Task.Yield();
        }
        transform.localPosition = targetPostion;
    }

    /// <summary>
    /// 旋转
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetRotate">目标旋转</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoRotate(this Transform transform, Quaternion targetRotate, float duration)
    {
        //if (Quaternion.Dot(transform.rotation, targetRotate) <= 0.01f)
        //{
        //    Debug.LogWarning("transform rotate is too close.");
        //    return;
        //}

        float startTime = Time.time;
        Quaternion startRotate = transform.rotation;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.rotation = Quaternion.Lerp(startRotate, targetRotate, lerp);
            await Task.Yield();
        }
        transform.rotation = targetRotate;
    }

    /// <summary>
    /// 旋转
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetRotate">目标旋转</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoRotate(this Transform transform, Vector3 targetRotate, float duration)
    {
        //if (Vector3.Dot(transform.eulerAngles, targetRotate) <= 0.01f)
        //{
        //    Debug.LogWarning("transform rotate is too close.");
        //    return;
        //}

        float startTime = Time.time;
        Vector3 startRotate = transform.eulerAngles;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.eulerAngles = Vector3.Lerp(startRotate, targetRotate, lerp);
            await Task.Yield();
        }
        transform.eulerAngles = targetRotate;
    }

    /// <summary>
    /// 本地旋转
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetRotate">目标旋转</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoLocalRotate(this Transform transform, Quaternion targetRotate, float duration)
    {
        //if (Quaternion.Dot(transform.localRotation, targetRotate) <= 0.01f)
        //{
        //    Debug.LogWarning("transform rotate is too close.");
        //    return;
        //}

        float startTime = Time.time;
        Quaternion startRotate = transform.localRotation;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.localRotation = Quaternion.Lerp(startRotate, targetRotate, lerp);
            await Task.Yield();
        }
        transform.localRotation = targetRotate;
    }

    /// <summary>
    /// 本地旋转
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetRotate">目标旋转</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoLocalRotate(this Transform transform, Vector3 targetRotate, float duration)
    {
        //if (Vector3.Dot(transform.localEulerAngles, targetRotate) <= 0.01f)
        //{
        //    Debug.LogWarning("transform rotate is too close.");
        //    return;
        //}

        float startTime = Time.time;
        Vector3 startRotate = transform.localEulerAngles;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.localEulerAngles = Vector3.Lerp(startRotate, targetRotate, lerp);
            await Task.Yield();
        }
        transform.localEulerAngles = targetRotate;
    }

    /// <summary>
    /// 缩放
    /// </summary>
    /// <param name="transform">Transform</param>
    /// <param name="targetScale">目标缩放</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoScale(this Transform transform, Vector3 targetScale, float duration)
    {
        if (Vector3.Distance(transform.localScale, targetScale) <= 0.01f)
        {
            Debug.LogWarning("transform scale is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startScale = transform.localScale;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            transform.localScale = Vector3.Lerp(startScale, targetScale, lerp);
            await Task.Yield();
        }
        transform.localScale = targetScale;
    }
    #endregion

    //UI
    #region RectTransfrom
    /// <summary>
    /// 锚点位置
    /// </summary>
    /// <param name="rectTransform">RectTransform</param>
    /// <param name="targetSizeDelta">目标锚定位置</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoAnchoredPosition(this RectTransform rectTransform, Vector2 targetAnchoredPosition, float duration)
    {
        if (Vector3.Distance(rectTransform.anchoredPosition, targetAnchoredPosition) <= 0.01f)
        {
            Debug.LogWarning("rectTransform anchoredPosition is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startAnchoredPosition = rectTransform.anchoredPosition;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            rectTransform.anchoredPosition = Vector3.Lerp(startAnchoredPosition, targetAnchoredPosition, lerp);
            await Task.Yield();
        }
        rectTransform.anchoredPosition = targetAnchoredPosition;
    }

    /// <summary>
    /// 大小
    /// </summary>
    /// <param name="rectTransform">RectTransform</param>
    /// <param name="targetSizeDelta">目标大小</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoSizeDelta(this RectTransform rectTransform, Vector2 targetSizeDelta, float duration)
    {
        if (Vector3.Distance(rectTransform.sizeDelta, targetSizeDelta) <= 0.01f)
        {
            Debug.LogWarning("rectTransform sizeDelta is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startSizeDelta = rectTransform.sizeDelta;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            rectTransform.sizeDelta = Vector3.Lerp(startSizeDelta, targetSizeDelta, lerp);
            await Task.Yield();
        }
        rectTransform.sizeDelta = targetSizeDelta;
    }
    #endregion

    #region Graphic
    /// <summary>
    /// 颜色渐变
    /// </summary>
    /// <param name="graphic">图形</param>
    /// <param name="targetColor">目标颜色</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoColor(this Graphic graphic, Color targetColor, float duration)
    {
        float startTime = Time.time;
        Color startColor = graphic.color;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            graphic.color = Color.Lerp(startColor, targetColor, lerp);
            await Task.Yield();
        }
        graphic.color = targetColor;
    }

    /// <summary>
    /// 透明度渐变
    /// </summary>
    /// <param name="graphic">图形</param>
    /// <param name="targetAlpha">目标透明度</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoFade(this Graphic graphic, float targetAlpha, float duration)
    {
        await graphic.DoColor(new Color(graphic.color.r, graphic.color.g, graphic.color.b, targetAlpha), duration);
    }
    #endregion

    #region Image
    /// <summary>
    /// 渐变FillAmount
    /// </summary>
    /// <param name="image">Image</param>
    /// <param name="targetFillAmount">目标FillAmount</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoFillAmount(this Image image, float targetFillAmount, float duration)
    {
        if (image.type != Image.Type.Filled)
        {
            Debug.LogWarning("image type is not filled.");
            return;
        }

        float startTime = Time.time;
        float startFillAmount = image.fillAmount;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            image.fillAmount = Mathf.Lerp(startFillAmount, targetFillAmount, lerp);
            await Task.Yield();
        }
        image.fillAmount = targetFillAmount;
    }
    #endregion

    #region Text
    /// <summary>
    /// 渐变Text
    /// </summary>
    /// <param name="text">Text</param>
    /// <param name="content">目标内容</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    [System.Obsolete]
    public static async Task DoText(this Text text, string content, float duration)
    {
        if (text.text == content)
        {
            Debug.LogWarning("text content is the same.");
            return;
        }

        float startTime = Time.time;
        string startContent = text.text;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            //获取当前字符串长度
            int currentLength = (int)Mathf.Lerp(startContent.Length, content.Length, lerp);

            //混合字符串
            string currentContent = string.Empty;
            if (currentLength > content.Length)
                currentContent = content + startContent.Substring(0, currentLength - content.Length);
            else
                currentContent = content.Substring(0, currentLength);

            if (currentContent != text.text)
                text.text = currentContent;
            await Task.Yield();
        }
        text.text = content;
    }
    #endregion

    #region Slide
    /// <summary>
    /// 渐变值
    /// </summary>
    /// <param name="slider">Slider</param>
    /// <param name="targetValue">目标值</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoValue(this Slider slider, float targetValue, float duration)
    {
        if (slider.value == targetValue)
        {
            Debug.LogWarning("slider value is the same.");
            return;
        }

        float startTime = Time.time;
        float startValue = slider.value;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            slider.value = Mathf.Lerp(startValue, targetValue, lerp);
            await Task.Yield();
        }
        slider.value = targetValue;
    }
    #endregion

    #region Scrollbar
    /// <summary>
    /// 渐变值
    /// </summary>
    /// <param name="scrollbar">Slider</param>
    /// <param name="targetValue">目标值</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoValue(this Scrollbar scrollbar, float targetValue, float duration)
    {
        if (scrollbar.value == targetValue)
        {
            Debug.LogWarning("Scrollbar value is the same.");
            return;
        }

        float startTime = Time.time;
        float startValue = scrollbar.value;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            scrollbar.value = Mathf.Lerp(startValue, targetValue, lerp);
            await Task.Yield();
        }
        scrollbar.value = targetValue;
    }
    #endregion

    #region ScrollRect
    /// <summary>
    /// 渐变水平值
    /// </summary>
    /// <param name="scrollRect">ScrollRect</param>
    /// <param name="targetValue">水平目标值</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoHorizontalValue(this ScrollRect scrollRect, float targetValue, float duration)
    {
        if (scrollRect.horizontalNormalizedPosition == targetValue)
        {
            Debug.LogWarning("scrollRect horizontal value is the same.");
            return;
        }

        float startTime = Time.time;
        float startValue = scrollRect.horizontalNormalizedPosition;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            scrollRect.horizontalNormalizedPosition = Mathf.Lerp(startValue, targetValue, lerp);
            await Task.Yield();
        }
        scrollRect.horizontalNormalizedPosition = targetValue;
    }

    /// <summary>
    /// 渐变垂直值
    /// </summary>
    /// <param name="scrollRect">ScrollRect</param>
    /// <param name="targetValue">垂直目标值</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoVerticalValue(this ScrollRect scrollRect, float targetValue, float duration)
    {
        if (scrollRect.horizontalNormalizedPosition == targetValue)
        {
            Debug.LogWarning("scrollRect vertical value is the same.");
            return;
        }

        float startTime = Time.time;
        float startValue = scrollRect.verticalNormalizedPosition;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            scrollRect.verticalNormalizedPosition = Mathf.Lerp(startValue, targetValue, lerp);
            await Task.Yield();
        }
        scrollRect.verticalNormalizedPosition = targetValue;
    }

    /// <summary>
    /// 渐变水平垂直值
    /// </summary>
    /// <param name="scrollRect">ScrollRect</param>
    /// <param name="targetHorizontalValue">水平目标值</param>
    /// <param name="targetVerticalValue">垂直目标值</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoHorizontalVerticalValue(this ScrollRect scrollRect, float targetHorizontalValue, float targetVerticalValue, float duration)
    {
        if (scrollRect.horizontalNormalizedPosition == targetHorizontalValue || scrollRect.verticalNormalizedPosition == targetVerticalValue)
        {
            Debug.LogWarning("scrollRect horizontal or vertical value is the same.");
            return;
        }

        float startTime = Time.time;
        float startHorizontalValue = scrollRect.horizontalNormalizedPosition;
        float startVerticalValue = scrollRect.verticalNormalizedPosition;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            scrollRect.horizontalNormalizedPosition = Mathf.Lerp(startHorizontalValue, targetHorizontalValue, lerp);
            scrollRect.verticalNormalizedPosition = Mathf.Lerp(startVerticalValue, targetVerticalValue, lerp);
            await Task.Yield();
        }
        scrollRect.horizontalNormalizedPosition = targetHorizontalValue;
        scrollRect.verticalNormalizedPosition = targetVerticalValue;
    }
    #endregion

    #region CanvasGroup
    /// <summary>
    /// 透明度渐变
    /// </summary>
    /// <param name="canvasGroup">CanvasGroup</param>
    /// <param name="targetAlpha">目标透明度</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoAlpha(this CanvasGroup canvasGroup, float targetAlpha, float duration)
    {
        if (Mathf.Approximately(canvasGroup.alpha, targetAlpha))
        {
            Debug.LogWarning("canvasGroup alpha is the same.");
            return;
        }

        float startTime = Time.time;
        float startAlpha = canvasGroup.alpha;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            canvasGroup.alpha = Mathf.Lerp(startAlpha, targetAlpha, lerp);
            await Task.Yield();
        }
        canvasGroup.alpha = targetAlpha;
    }
    #endregion

    //3D物理
    #region BoxClooider
    /// <summary>
    /// 盒碰撞体大小
    /// </summary>
    /// <param name="boxCollider">BoxCollider</param>
    /// <param name="targetSize">目标碰撞体大小</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoSize(this BoxCollider boxCollider, Vector3 targetSize, float duration)
    {
        if (Vector3.Distance(boxCollider.size, targetSize) <= 0.01f)
        {
            Debug.LogWarning("boxCollider size is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startSize = boxCollider.size;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            boxCollider.size = Vector3.Lerp(startSize, targetSize, lerp);
            await Task.Yield();
        }
        boxCollider.size = targetSize;
    }

    /// <summary>
    /// 盒碰撞体中心
    /// </summary>
    /// <param name="boxCollider">BoxCollider</param>
    /// <param name="targetCenter">目标碰撞体中心</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoCenter(this BoxCollider boxCollider, Vector3 targetCenter, float duration)
    {
        if (Vector3.Distance(boxCollider.center, targetCenter) <= 0.01f)
        {
            Debug.LogWarning("boxCollider center is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startCenter = boxCollider.center;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            boxCollider.center = Vector3.Lerp(startCenter, targetCenter, lerp);
            await Task.Yield();
        }
        boxCollider.center = targetCenter;
    }
    #endregion

    #region SphereCollider
    /// <summary>
    /// 球型碰撞体半径
    /// </summary>
    /// <param name="sphereCollider">SphereCollider</param>
    /// <param name="targetRadius">目标半径</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoRadius(this SphereCollider sphereCollider, float targetRadius, float duration)
    {
        if (Mathf.Approximately(sphereCollider.radius, targetRadius))
        {
            Debug.LogWarning("SphereCollider radius is too close.");
            return;
        }

        float startTime = Time.time;
        float startRadius = sphereCollider.radius;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            sphereCollider.radius = Mathf.Lerp(startRadius, targetRadius, lerp);
            await Task.Yield();
        }
        sphereCollider.radius = targetRadius;
    }

    /// <summary>
    /// 球型碰撞体中心
    /// </summary>
    /// <param name="sphereCollider">SphereCollider</param>
    /// <param name="targetCenter">目标碰撞体中心</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoCenter(this SphereCollider sphereCollider, Vector3 targetCenter, float duration)
    {
        if (Vector3.Distance(sphereCollider.center, targetCenter) <= 0.01f)
        {
            Debug.LogWarning("sphereCollider center is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startCenter = sphereCollider.center;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            sphereCollider.center = Vector3.Lerp(startCenter, targetCenter, lerp);
            await Task.Yield();
        }
        sphereCollider.center = targetCenter;
    }
    #endregion

    #region CapsuleCollider
    /// <summary>
    /// 胶囊碰撞体半径
    /// </summary>
    /// <param name="capsuleCollider">CapsuleCollider</param>
    /// <param name="targetRadius">目标半径</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoRadius(this CapsuleCollider capsuleCollider, float targetRadius, float duration)
    {
        if (Mathf.Approximately(capsuleCollider.radius, targetRadius))
        {
            Debug.LogWarning("capsuleCollider radius is too close.");
            return;
        }

        float startTime = Time.time;
        float startRadius = capsuleCollider.radius;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            capsuleCollider.radius = Mathf.Lerp(startRadius, targetRadius, lerp);
            await Task.Yield();
        }
        capsuleCollider.radius = targetRadius;
    }

    /// <summary>
    /// 胶囊碰撞体高度
    /// </summary>
    /// <param name="capsuleCollider">CapsuleCollider</param>
    /// <param name="targetHeight">目标半径</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoHeight(this CapsuleCollider capsuleCollider, float targetHeight, float duration)
    {
        if (Mathf.Approximately(capsuleCollider.height, targetHeight))
        {
            Debug.LogWarning("capsuleCollider height is too close.");
            return;
        }

        float startTime = Time.time;
        float startHeight = capsuleCollider.height;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            capsuleCollider.height = Mathf.Lerp(startHeight, targetHeight, lerp);
            await Task.Yield();
        }
        capsuleCollider.height = targetHeight;
    }

    /// <summary>
    /// 胶囊碰撞体中心
    /// </summary>
    /// <param name="capsuleCollider">CapsuleCollider</param>
    /// <param name="targetCenter">目标碰撞体中心</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoCenter(this CapsuleCollider capsuleCollider, Vector3 targetCenter, float duration)
    {
        if (Vector3.Distance(capsuleCollider.center, targetCenter) <= 0.01f)
        {
            Debug.LogWarning("capsuleCollider center is too close.");
            return;
        }

        float startTime = Time.time;
        Vector3 startCenter = capsuleCollider.center;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            capsuleCollider.center = Vector3.Lerp(startCenter, targetCenter, lerp);
            await Task.Yield();
        }
        capsuleCollider.center = targetCenter;
    }
    #endregion

    //VideoPlayer
    #region VideoPlayer
    /// <summary>
    /// 透明度渐变
    /// </summary>
    /// <param name="videoPlayer">VideoPlayer</param>
    /// <param name="targetAlpha">目标透明度</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoAlpha(this VideoPlayer videoPlayer, float targetAlpha, float duration)
    {
        if (videoPlayer.renderMode != VideoRenderMode.CameraNearPlane & videoPlayer.renderMode != VideoRenderMode.CameraFarPlane)
        {
            Debug.LogWarning("videoPlayer renderMode not is cameraNearPlane or cameraFarPlane.");
            return;
        }

        if (Mathf.Approximately(videoPlayer.targetCameraAlpha, targetAlpha))
        {
            Debug.LogWarning("videoPlayer targetCameraAlpha is too close.");
            return;
        }

        float startTime = Time.time;
        float startAlpha = videoPlayer.targetCameraAlpha;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            videoPlayer.targetCameraAlpha = Mathf.Lerp(startAlpha, targetAlpha, lerp);
            await Task.Yield();
        }
        videoPlayer.targetCameraAlpha = targetAlpha;
    }

    /// <summary>
    /// 播放速度
    /// </summary>
    /// <param name="videoPlayer">VideoPlayer</param>
    /// <param name="targetSpeed">目标播放速度</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoPlaybackSpeed(this VideoPlayer videoPlayer, float targetSpeed, float duration)
    {
        if (Mathf.Approximately(videoPlayer.playbackSpeed, targetSpeed))
        {
            Debug.LogWarning("videoPlayer playbackSpeed is too close.");
            return;
        }

        float startTime = Time.time;
        float startSpeed = videoPlayer.playbackSpeed;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            videoPlayer.playbackSpeed = Mathf.Lerp(startSpeed, targetSpeed, lerp);
            await Task.Yield();
        }
        videoPlayer.playbackSpeed = targetSpeed;
    }
    #endregion

    //AudioSource
    #region AudioSource
    /// <summary>
    /// 音量
    /// </summary>
    /// <param name="audioSource">VideoPlayer</param>
    /// <param name="targetVolume">目标音量</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoVolume(this AudioSource audioSource, float targetVolume, float duration)
    {
        if (Mathf.Approximately(audioSource.volume, targetVolume))
        {
            Debug.LogWarning("audioSource volume is too close.");
            return;
        }

        float startTime = Time.time;
        float startVolume = audioSource.volume;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            audioSource.volume = Mathf.Lerp(startVolume, targetVolume, lerp);
            await Task.Yield();
        }
        audioSource.volume = targetVolume;
    }
    #endregion

    //Camera
    #region Camera
    /// <summary>
    /// 相机背景色
    /// </summary>
    /// <param name="camera">Camera</param>
    /// <param name="targetFOV">目标背景色</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoBackgroundColor(this Camera camera, Color targetBackgroundColor, float duration)
    {
        if (camera.clearFlags != CameraClearFlags.Skybox & camera.clearFlags != CameraClearFlags.SolidColor)
            Debug.LogWarning("camera clearFlags not is skybox or solidColor.");

        float startTime = Time.time;
        Color startBackgroundColor = camera.backgroundColor;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            camera.backgroundColor = Color.Lerp(startBackgroundColor, targetBackgroundColor, lerp);
            await Task.Yield();
        }
        camera.backgroundColor = targetBackgroundColor;
    }

    /// <summary>
    /// 相机FOV
    /// </summary>
    /// <param name="camera">Camera</param>
    /// <param name="targetFOV">目标FOV</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoFOV(this Camera camera, float targetFOV, float duration)
    {
        if (camera.orthographic)
        {
            Debug.LogWarning("camera not is perspective.");
            return;
        }

        float startTime = Time.time;
        float startFov = camera.fieldOfView;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            camera.fieldOfView = Mathf.Lerp(startFov, targetFOV, lerp);
            await Task.Yield();
        }
        camera.fieldOfView = targetFOV;
    }

    /// <summary>
    /// 相机Size
    /// </summary>
    /// <param name="camera">Camera</param>
    /// <param name="targetSize">目标FOV</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoSize(this Camera camera, float targetSize, float duration)
    {
        if (!camera.orthographic)
        {
            Debug.LogWarning("camera not is orthographic.");
            return;
        }

        float startTime = Time.time;
        float startSize = camera.orthographicSize;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            camera.orthographicSize = Mathf.Lerp(startSize, targetSize, lerp);
            await Task.Yield();
        }
        camera.orthographicSize = targetSize;
    }
    #endregion

    //Light
    #region Light
    /// <summary>
    /// 颜色渐变
    /// </summary>
    /// <param name="light">Light</param>
    /// <param name="targetIntensity">目标颜色</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoColor(this Light light, Color targetColor, float duration)
    {
        float startTime = Time.time;
        Color startColor = light.color;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            light.color = Color.Lerp(startColor, targetColor, lerp);
            await Task.Yield();
        }
        light.color = targetColor;
    }

    /// <summary>
    /// 光照强度渐变
    /// </summary>
    /// <param name="light">Light</param>
    /// <param name="targetIntensity">目标强度</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoIntensity(this Light light, float targetIntensity, float duration)
    {
        float startTime = Time.time;
        float startIntensity = light.intensity;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            light.intensity = Mathf.Lerp(startIntensity, targetIntensity, lerp);
            await Task.Yield();
        }
        light.intensity = targetIntensity;
    }

    /// <summary>
    /// 光照范围
    /// </summary>
    /// <param name="light">Light</param>
    /// <param name="targetRange">目标光照范围</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoRange(this Light light, float targetRange, float duration)
    {
        if (light.type != LightType.Spot & light.type != LightType.Point)
        {
            Debug.LogWarning("light type not is spot or point.");
            return;
        }

        float startTime = Time.time;
        float startRange = light.range;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            light.range = Mathf.Lerp(startRange, targetRange, lerp);
            await Task.Yield();
        }
        light.range = targetRange;
    }

    /// <summary>
    /// 光照角度
    /// </summary>
    /// <param name="light">Light</param>
    /// <param name="targetRange">目标光照角度</param>
    /// <param name="duration">持续时间</param>
    /// <returns></returns>
    public static async Task DoAngle(this Light light, float targetAngle, float duration)
    {
        if (light.type != LightType.Spot)
        {
            Debug.LogWarning("light type not is spot.");
            return;
        }

        float startTime = Time.time;
        float startAngle = light.spotAngle;
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            light.spotAngle = Mathf.Lerp(startAngle, targetAngle, lerp);
            await Task.Yield();
        }
        light.spotAngle = targetAngle;
    }
    #endregion

    //Animator
    /// <summary>
    /// 重置状态
    /// </summary>
    /// <param name="animator">送花状态机</param>
    /// <param name="firstStateName">重置状态的名称</param>
    public static void ResetState(this Animator animator, string firstStateName)
    {
        animator.Play(firstStateName, 0);
        animator.Update(0.0f);
    }

    /// <summary>
    /// TO
    /// </summary>
    /// <param name="gameObject"></param>
    /// <param name="getter"></param>
    /// <param name="setter"></param>
    /// <param name="targetValue"></param>
    /// <param name="duration"></param>
    /// <returns></returns>
    public static async Task To(this GameObject gameObject, Func<float> getter, Action<float> setter, float targetValue, float duration)
    {
        float startTime = Time.time;
        float startValue = getter();
        float elapsedTime = 0.0f;
        while (elapsedTime <= duration)
        {
            float currentTime = Time.time;
            elapsedTime = currentTime - startTime;
            float lerp = Mathf.Clamp01(elapsedTime / duration);
            setter(Mathf.Lerp(startValue, targetValue, lerp));
            await Task.Yield();
        }
        setter(targetValue);
    }
}